import os

class auto_codes(object):
    def __init__(self):
        self.type = "c"
        self.target = input('请输入工程名：')
        self.headers = []
        self.head_file = ""
        self.src_file = ""
        self.src_data = []
        self.head_data = []
        self.output_path = "output/" + self.target
        if not os.path.exists(self.output_path):
            os.makedirs(self.output_path)

        self.target_statement = '''
struct %(target)s_config{
    uint32_t id;
    uint32_t enable;
    /*param*/
};

struct %(target)s;

enum %(TARGET)s_EVENT
{
    %(TARGET)s_EVENT_NONE = 0,
    %(TARGET)s_EVENT_TEST,
    %(TARGET)s_EVENT_MAX,
};

typedef int32_t (*%(target)s_event_notify)(struct %(target)s*, int32_t, void*, void*);

struct %(target)s_event_action
{
    %(target)s_event_notify notify;
    void* object;
    struct %(target)s_event_action* next;
};

struct %(target)s_operation
{
    int32_t (*init)(struct %(target)s*);
    int32_t (*release)(struct %(target)s*);

    int32_t (*start)(struct %(target)s*, struct %(target)s_config *);
    int32_t (*stop)(struct %(target)s*);

    int32_t (*register_notify)(struct %(target)s*, int32_t, %(target)s_event_notify notify, void*);
    int32_t (*unregister_notify)(struct %(target)s*, int32_t, void*);
    int32_t (*trigger_notify)(struct %(target)s*, int32_t, void*);
};

struct %(target)s
{
    struct list_head head;
    wait_t wait;
    lock_t lock;
    lock_t notify_lock;

    int running_flag;
    pthread_t pid;

    uint8_t id;
    uint8_t enable;

    struct %(target)s_operation* op;
    struct %(target)s_event_action *paction[%(TARGET)s_EVENT_MAX];
    
    /*private*/
    
    /*public*/
    struct %(target)s_config *pcfg;
};

int32_t create_init_%(target)s(struct %(target)s** p%(target)s);
void release_destroy_%(target)s(struct %(target)s* p%(target)s);
        '''
        self.target_define = '''
#define %(TARGET)s_VER_MAJOR  (1)
#define %(TARGET)s_VER_MINOR  (0)
#define %(TARGET)s_VER_PATCH  (0)

static int32_t %(target)s_start(struct %(target)s* p%(target)s, struct %(target)s_config *pcfg)
{
    int32_t ret = 0;
    
    p%(target)s->pcfg = pcfg;

    /*
    start modules task
    ......
    */
    
    return ret;
}

static int32_t %(target)s_stop(struct %(target)s* p%(target)s)
{
    int32_t ret = 0;

    /*
    stop module task
    ......
    */

    return ret;
}

static int32_t %(target)s_init(struct %(target)s* p%(target)s)
{
    int32_t ret = 0;

    printf("%(TARGET)s VERSION:V%%d.%%d.%%d [%%s %%s]", %(TARGET)s_VER_MAJOR, %(TARGET)s_VER_MINOR, %(TARGET)s_VER_PATCH, __DATE__, __TIME__);

    INIT_LIST_HEAD(&(p%(target)s->head));
    lock_init(&(p%(target)s->lock));
    lock_init(&(p%(target)s->notify_lock));
    wait_init(&(p%(target)s->wait));

    /*
    create all sources
    ......
    */
    
    return ret;
}

static int32_t %(target)s_release(struct %(target)s* p%(target)s)
{
    /*
    free all sources
    ......
    */

    lock_destroy((&p%(target)s->notify_lock));
    lock_destroy((&p%(target)s->lock));
    wait_destroy((&p%(target)s->wait));

    return 0;
}

static int32_t %(target)s_register_notify(struct %(target)s* p%(target)s, int32_t event, %(target)s_event_notify notify, void* object)
{
    struct %(target)s_event_action* paction;
    if(!notify || (event <= %(TARGET)s_EVENT_NONE) || (event >= %(TARGET)s_EVENT_MAX)){
        return -EINVAL;
    }
    paction = (struct %(target)s_event_action*)malloc(sizeof(struct %(target)s_event_action));
    if(!paction){
        return -ENOMEM;
    }
    paction->notify = notify;
    paction->object = object;
    lock(&(p%(target)s->notify_lock));
    paction->next = p%(target)s->paction[event];
    p%(target)s->paction[event] = paction;
    unlock(&(p%(target)s->notify_lock));
    return 0;
}

static int32_t %(target)s_unregister_notify(struct %(target)s* p%(target)s, int32_t event, void* object)
{
    struct %(target)s_event_action *paction,* ptmp;
    if((event <= %(TARGET)s_EVENT_NONE) || (event >= %(TARGET)s_EVENT_MAX)){
        return -EINVAL;
    }
    lock(&(p%(target)s->notify_lock));
    paction = p%(target)s->paction[event];
    if(paction){
        if(paction->object == object){
            p%(target)s->paction[event] = paction->next;
            free(paction);
        }else{
            while(paction->next){
                if(paction->next->object == object){
                    ptmp = paction->next;
                    paction->next = ptmp->next;
                    free(ptmp);
                    break;
                }
                paction = paction->next;
            }
        }
    }
    unlock(&(p%(target)s->notify_lock));

    return 0;
}

static int32_t %(target)s_trigger_notify(struct %(target)s* p%(target)s, int32_t event, void* context)
{
    struct %(target)s_event_action* paction;
    if((event <= %(TARGET)s_EVENT_NONE) || (event >= %(TARGET)s_EVENT_MAX)){
        return -EINVAL;
    }
    lock(&(p%(target)s->notify_lock));
    paction = p%(target)s->paction[event];
    while(paction){
        paction->notify(p%(target)s, event, paction->object, context);
        paction = paction->next;
    }
    unlock(&(p%(target)s->notify_lock));

    return 0;
}

static struct %(target)s_operation %(target)s_op =
{
    .init = %(target)s_init,
    .release = %(target)s_release,

    .start = %(target)s_start,
    .stop = %(target)s_stop,

    .register_notify = %(target)s_register_notify,
    .unregister_notify = %(target)s_unregister_notify,
    .trigger_notify = %(target)s_trigger_notify,
};

int32_t create_init_%(target)s(struct %(target)s** p%(target)s)
{
    int32_t ret;
    struct %(target)s* ptmp;
    (*p%(target)s) = (struct %(target)s*)malloc(sizeof(struct %(target)s));
    if(!(*p%(target)s)){
        return -ENOMEM;
    }
    ptmp = *p%(target)s;
    memset(ptmp, 0, sizeof(struct %(target)s));
    ptmp->op = &%(target)s_op;
    ret = ptmp->op->init(ptmp);
    if(ret < 0){
        release_destroy_%(target)s(ptmp);
        return ret;
    }
    return 0;
}

void release_destroy_%(target)s(struct %(target)s* p%(target)s)
{
    if(p%(target)s){
        p%(target)s->op->release(p%(target)s);
        free(p%(target)s);
    }
}
        '''

    def add_head_null_string(self):
        self.head_data.append("\n")

    def add_src_null_string(self):
        self.src_data.append("\n")

    def add_compile_define(self):
        define = "__%s_H__" %(str(self.target).upper())
        data = "#ifndef %s" %(define)
        print(data)
        self.head_data.append(data + "\n")
        data = "#define %s" %(define)
        print(data)
        self.head_data.append(data + "\n")

    def add_compile_define_end(self):
        self.head_data.append("#ifdef __cplusplus" + "\n")
        self.head_data.append("}" + "\n")
        self.head_data.append("#endif" + "\n\n")

        self.head_data.append("#endif" + "\n")

    def add_headers(self):
        self.headers.append("#ifdef __cplusplus" + "\n")
        self.headers.append('extern "C" {' + "\n")
        self.headers.append("#endif" + "\n\n")

        self.headers.append("#include <stdint.h>" + "\n")
        self.headers.append("#include <stdlib.h>" + "\n")
        self.headers.append("#include <string.h>" + "\n")
        self.headers.append("#include <errno.h>" + "\n")

        self.headers.append('#include "list.h"' + "\n")
        self.headers.append('#include "lock.h"' + "\n")
        self.headers.append('#include "wait.h"' + "\n")
        self.headers.append('#include "log.h"' + "\n")

    def add_head_headers(self):
        for data in self.headers:
            self.head_data.append(data)

    def add_module_statement(self):
        data = self.target_statement %{'target':self.target,'TARGET':str(self.target).upper()}
        print(data)
        self.head_data.append(data)

    def write_head_data(self, file):
        self.add_compile_define()
        self.add_head_null_string()

        self.add_headers()
        self.add_head_headers()
        self.add_head_null_string()

        self.add_module_statement()
        self.add_head_null_string()

        self.add_compile_define_end()

        for data in self.head_data:
            file.write(data)

    def add_module_define(self):
        data = self.target_define %{'target':self.target,'TARGET':str(self.target).upper()}
        print(data)
        self.src_data.append(data)

    def write_src_data(self, file):
        header = '#include "%s"' %(self.head_file)
        self.src_data.append(header + "\n")

        self.add_src_null_string()

        self.add_module_define()

        for data in self.src_data:
            file.write(data)

    def create_head_file(self):
        file = open(self.output_path + "/" + self.head_file, "w")
        self.write_head_data(file)
        file.close()

    def create_src_file(self):
        file = open(self.output_path + "/" + self.src_file, "w")
        self.write_src_data(file)
        file.close()

    def create_target(self):
        if self.type == "c":
            self.head_file = self.target + "." + "h"
            print(self.head_file)
            self.create_head_file()

        self.src_file = self.target + "." + self.type
        self.create_src_file()


if __name__ == '__main__':
    codes = auto_codes()
    # codes.add_module_define()
    while (codes.target == ""):
        codes.target = input('请输入工程名：')
    codes.create_target()
